﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Nexterday.Linq.Autocompiler;
using System.Collections.Specialized;
using System.IO;
using System.Text.RegularExpressions;
using System.Data.Objects;

namespace Nexterday.Linq.Autocompiler.EF4.Tests
{
    [TestFixture]
    public class QueryTests
    {

        [Test]
        public void Can_Select_With_Joins()
        {
            using (NorthwindEntities db = new NorthwindEntities())
            {
                var cat = (from p in db.Products.AsCompilable() 
                               join c in db.Categories.AsCompilable() on p.CategoryID equals c.CategoryID
                               where c.Description!=null
                               orderby c.CategoryID
                                   select c
                                   ).First();
                Assert.AreEqual(1, cat.CategoryID);
            }
        }
        
        [Test]
        public void Can_Select_Single_Product()
        {
            using (NorthwindEntities db = new NorthwindEntities())
            {
                var product = (from p in db.GetCompiled(x=>x.Products) where p.ProductID == 1 select p).Single();
                Assert.AreEqual(1, product.ProductID);
            }
        }

        //[Test]
        //public void Executes_Same_Sql_Query_As_Standard_Provider()
        //{
        //    string sql1, sql2;
        //    using (StringWriter sw = new StringWriter())
        //    {
        //        using (NorthwindEntities db = new NorthwindEntities())
        //        {
        //            db.Log = sw;
        //            var product = (from p in db.Products where p.ProductID == 1 select p).Single();
        //            Assert.AreEqual(1, product.ProductID);
        //        }
        //        sql1 = sw.ToString();
        //    }
        //    using (StringWriter sw = new StringWriter())
        //    {
        //        using (NorthwindEntities db = new NorthwindEntities())
        //        {
        //            db.Log = sw;
        //            var product = (from p in db.GetCompiled(x=>x.Products) where p.ProductID == 1 select p).Single();
        //            Assert.AreEqual(1, product.ProductID);
        //        }
        //        sql2 = sw.ToString();
        //    }

        //    Assert.AreEqual(sql1, sql2);
        //}

        [Test]
        public void Can_Select_Top_5_Products_Ordered_By_ProductID()
        {
            using (NorthwindEntities db = new NorthwindEntities())
            {
                var products = db.GetCompiled(x=>x.Products).OrderBy(x => x.ProductID).Take(5).ToList();
                Assert.AreEqual(5, products.Count());
            }
        }

        [Test]
        public void Can_Select_Products_Ordered_By_ProductID_Using_Linq_Syntax()
        {
            using (NorthwindEntities db = new NorthwindEntities())
            {
                var products = (from t in db.GetCompiled(x=>x.Products) orderby t.ProductID select t).ToList();
                Assert.AreEqual(1, products.First().ProductID);
                Assert.AreEqual(2, products.Skip(1).First().ProductID);
            }
        }

        [Test]
        public void Can_Select_Two_Different_Types_With_Equally_Named_Properties()
        {
            using (NorthwindEntities db = new NorthwindEntities())
            {
                Assert.DoesNotThrow(() =>
                {
                    var products = db.GetCompiled(x => x.Customers).Select(x => x.Orders.First());
                    var categories = db.GetCompiled(x => x.Employees).Select(x => x.Orders.First());
                });
            }
        }

        [Test]
        public void Can_Select_Projection_To_Anonymous_Class()
        {
            using (NorthwindEntities db = new NorthwindEntities())
            {
                Assert.DoesNotThrow(() =>
                {
                    var products = from c in db.GetCompiled(x => x.Customers)
                                   select new { c.City, c.Phone };
                    var results = products.ToList();
                });
            }
        }

        //[Test]
        //public void Can_Select_Projection_To_Existing_Class()
        //{
        //    using (NorthwindEntities db = new NorthwindEntities())
        //    {
        //        //Assert.DoesNotThrow(() =>
        //        //{
        //            var products = from c in db.Customers.GetCompiled(x=>x.Products)
        //                           select new FileInfo(c.CompanyName);
        //            var results = products.ToList();
        //            Assert.IsTrue(results.Count > 0);
        //        //});
        //    }
        //}

        [Test]
        public void Can_Select_Single_Product_Based_On_Parameter()
        {
            using (NorthwindEntities db = new NorthwindEntities())
            {
                int productId = 1;
                var product = (from p in db.GetCompiled(x=>x.Products)
                               where p.ProductID == productId
                               select p).Single();
                Assert.AreEqual(1, product.ProductID);
            }
        }

        [Test]
        public void Can_Select_Single_Product_Based_On_FuncCall()
        {
            using (NorthwindEntities db = new NorthwindEntities())
            {
                Func<int> productId = ()=> 1;
                var product = (from p in db.GetCompiled(x=>x.Products)
                               where p.ProductID == productId.Invoke()
                               select p).Single();
                Assert.AreEqual(1, product.ProductID);
            }
        }

        private int GetProductId()
        {
            return 1;
        }

        [Test]
        public void Can_Select_Single_Product_Based_On_Local_Method()
        {
            using (NorthwindEntities db = new NorthwindEntities())
            {
                Func<int> productId = () => 1;
                var product = (from p in db.GetCompiled(x=>x.Products)
                               where p.ProductID == GetProductId()
                               select p).Single();
                Assert.AreEqual(1, product.ProductID);
            }
        }

        [Test]
        public void Can_Select_Joined()
        {
            using (NorthwindEntities db = new NorthwindEntities())
            {
                var orders = (from p in db.GetCompiled(x=>x.Products)
                              from c in p.Order_Details
                              select c.Order).Distinct();
                Assert.AreEqual(830, orders.Count());
            }
        }



        [Test]
        public void Can_Select_Single_Product_Based_On_Value_In_NameValueCollection()
        {
            NameValueCollection col = new NameValueCollection();
            col["ProductId"] = "1";
            using (NorthwindEntities db = new NorthwindEntities())
            {
                var product = (from p in db.GetCompiled(x=>x.Products)
                               where p.ProductID == int.Parse(col["ProductId"])
                               select p).Single();
                Assert.AreEqual(1, product.ProductID);
            }
        }

        [Test]
        public void Can_Select_Single_Product_Based_On_Many_Parameters()
        {
            using (NorthwindEntities db = new NorthwindEntities())
            {
                int productId = 1;
                int productId2 = -1;
                int productId3 = -1;
                int productId4 = -1;
                int productId5 = -1;
                var product = (from p in db.GetCompiled(x=>x.Products)
                               where p.ProductID == productId ||
                               p.ProductID == productId2 ||
                               p.ProductID == productId3 ||
                               p.ProductID == productId4 ||
                               p.ProductID == productId5
                               select p).Single();
                Assert.AreEqual(1, product.ProductID);
            }
        }

        //[Test]
        //public void Cant_Select_Products_Based_On_Array_Of_Parameters_When_SupportEnumerableParameters_Is_False()
        //{
        //    Assert.Throws(typeof(NotSupportedException), () =>
        //    {
        //        using (NorthwindEntities db = new NorthwindEntities())
        //        {
        //            var productIds = Enumerable.Range(1, 5);

        //            var count = (from p in db.Products.AsCompilable(new CompilationParameters
        //            {
        //                SupportEnumerableParameters = false
        //            })
        //                         where productIds.Contains(p.ProductID)
        //                         select p).Count();

        //        }
        //    });
        //}

        [Test]
        public void Can_Select_Products_Based_On_Array_Of_Parameters_When_SupportEnumerableParameters_Is_True()
        {
            using (NorthwindEntities db = new NorthwindEntities())
            {
                var productIds = Enumerable.Range(1, 5);

                var count = (from p in db.GetCompiled(x => x.Products,new CompilationParameters
                {
                    SupportEnumerableParameters = true
                })
                             where productIds.Contains(p.ProductID)
                             select p).Count();
                Assert.AreEqual(5, count);
            }
        }


        //[Test]
        //public void Can_Select_Category_Based_On_Product_Parameter()
        //{
        //    using (NorthwindEntities db = new NorthwindEntities())
        //    {
        //        var product = db.Products.First();
        //        var categories = (from p in db.Categories.GetCompiled(x=>x.Products)
        //                          where p.Products.Any(x => x == product)
        //                          select p).ToList();
        //        Assert.That(categories.Count == 1);
        //    }
        //}
    }
}
